#!/bin/bash

#########################################################
# Debian 12 高级网络入侵防护脚本 - 优化版               #
# 修复了规则顺序和链调用问题                            #
#########################################################

# 变量定义
IPTABLES="/sbin/iptables"
IP6TABLES="/sbin/ip6tables"
MODPROBE="/sbin/modprobe"
SYSCTL="/sbin/sysctl"
LOG_DIR="/var/log/firewall"
FAIL2BAN_JAIL="/etc/fail2ban/jail.d/firewall.conf"

# 优化防护参数
MAX_CONN_PER_IP=50
MAX_NEW_CONN_PER_IP=20
MAX_SSH_CONN_PER_IP=3
PORTSCAN_LIMIT=3
SYN_FLOOD_LIMIT=20

# 定义允许开放的端口数组
declare -A OPEN_PORTS=(
    ["SSH"]="22"
    ["HTTP"]="80"
    ["HTTPS"]="443"
    ["DNS"]="53"
    ["CUSTOM"]="22666"
)

# P2P端口范围（特殊处理）
P2P_TCP_PORTS="6881:6890"
P2P_UDP_PORTS="6881:6890"

# 创建日志和监控目录
mkdir -p $LOG_DIR/{attack,traffic,scan}
touch $LOG_DIR/firewall.log

# 加载安全模块
$MODPROBE nf_conntrack
$MODPROBE xt_connlimit
$MODPROBE xt_recent
$MODPROBE nf_conntrack_netlink

#########################################################
# 函数：检查软件是否已安装                              #
#########################################################

check_and_install() {
    local package=$1
    if ! dpkg -l | grep -q "^ii  $package"; then
        echo "安装 $package..."
        apt update >/dev/null 2>&1
        apt install -y $package >/dev/null 2>&1
        echo "$package 安装完成"
    else
        echo "$package 已安装，跳过安装"
    fi
}

check_command_exists() {
    local command=$1
    local package=$2
    if ! command -v $command &> /dev/null; then
        echo "安装 $package..."
        apt update >/dev/null 2>&1
        apt install -y $package >/dev/null 2>&1
        echo "$package 安装完成"
    else
        echo "$package 已安装"
    fi
}

#########################################################
# 高级内核安全参数                                      #
#########################################################

# 增强型SYN洪水防护
$SYSCTL -w net.ipv4.tcp_syncookies=2
$SYSCTL -w net.ipv4.tcp_synack_retries=2
$SYSCTL -w net.ipv4.tcp_syn_retries=2

# 连接跟踪优化
$SYSCTL -w net.netfilter.nf_conntrack_max=2000000
$SYSCTL -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10
$SYSCTL -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10

# 安全加固
$SYSCTL -w net.ipv4.conf.all.log_martians=1
$SYSCTL -w net.ipv4.icmp_ignore_bogus_error_responses=1
$SYSCTL -w net.ipv4.tcp_rfc1337=1

#########################################################
# 创建专用防护链                                        #
#########################################################

# 清空现有规则
$IPTABLES -F
$IPTABLES -X
$IPTABLES -t nat -F
$IPTABLES -t nat -X
$IPTABLES -t mangle -F
$IPTABLES -t mangle -X

# 创建防护链
$IPTABLES -N PORTSCAN_DETECT
$IPTABLES -N SYN_FLOOD
$IPTABLES -N BRUTE_FORCE
$IPTABLES -N HTTP_PROTECT
$IPTABLES -N BLOCKLIST

# 默认策略
$IPTABLES -P INPUT DROP
$IPTABLES -P FORWARD DROP
$IPTABLES -P OUTPUT ACCEPT

#########################################################
# 基础防护规则（正确的顺序）                            #
#########################################################

# 1. 允许回环和已建立连接
$IPTABLES -A INPUT -i lo -j ACCEPT
$IPTABLES -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 2. 连接数限制（放在端口开放之前）
$IPTABLES -A INPUT -p tcp --syn -m connlimit --connlimit-above $MAX_CONN_PER_IP -j REJECT --reject-with tcp-reset
$IPTABLES -A INPUT -p tcp --syn -m limit --limit $MAX_NEW_CONN_PER_IP/s -j ACCEPT

# 3. 防护检测规则
$IPTABLES -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j PORTSCAN_DETECT
$IPTABLES -A INPUT -p tcp --tcp-flags ALL NONE -j PORTSCAN_DETECT
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j PORTSCAN_DETECT
$IPTABLES -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j PORTSCAN_DETECT
$IPTABLES -A INPUT -p tcp --syn -j SYN_FLOOD

# SSH暴力破解防护
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["SSH"]} -m state --state NEW -m recent --set --name sshbf
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["SSH"]} -m state --state NEW -m recent --update --seconds 60 --hitcount $MAX_SSH_CONN_PER_IP --name sshbf -j LOG --log-prefix "SSH_BF: "
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["SSH"]} -m state --state NEW -m recent --update --seconds 60 --hitcount $MAX_SSH_CONN_PER_IP --name sshbf -j DROP

# HTTP暴力破解防护
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["HTTP"]} -m recent --set --name httpbf
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["HTTP"]} -m recent --update --seconds 60 --hitcount 100 --name httpbf -j LOG --log-prefix "HTTP_BF: "
$IPTABLES -A INPUT -p tcp --dport ${OPEN_PORTS["HTTP"]} -m recent --update --seconds 60 --hitcount 100 --name httpbf -j DROP

#########################################################
# 服务端口开放（放在防护规则之后）                      #
#########################################################

open_ports() {
    echo "开放预设端口..."
    
    # 开放TCP端口
    for service in "${!OPEN_PORTS[@]}"; do
        port=${OPEN_PORTS[$service]}
        echo "开放 $service 端口: $port/tcp"
        $IPTABLES -A INPUT -p tcp --dport $port -j ACCEPT
    done
    
    # 特殊处理：只开放UDP的DNS端口
    if [[ -n "${OPEN_PORTS["DNS"]}" ]]; then
        echo "开放 DNS 端口: ${OPEN_PORTS["DNS"]}/udp"
        $IPTABLES -A INPUT -p udp --dport ${OPEN_PORTS["DNS"]} -j ACCEPT
    fi
    
    # P2P服务（限制连接数）
    if [[ -n "$P2P_TCP_PORTS" ]]; then
        echo "开放 P2P TCP 端口: $P2P_TCP_PORTS (限制连接数)"
        $IPTABLES -A INPUT -p tcp --dport $P2P_TCP_PORTS -m connlimit --connlimit-above 50 -j REJECT
        $IPTABLES -A INPUT -p tcp --dport $P2P_TCP_PORTS -j ACCEPT
    fi
    
    if [[ -n "$P2P_UDP_PORTS" ]]; then
        echo "开放 P2P UDP 端口: $P2P_UDP_PORTS"
        $IPTABLES -A INPUT -p udp --dport $P2P_UDP_PORTS -j ACCEPT
    fi
}

# 调用端口开放函数
open_ports

#########################################################
# 防护链的具体规则                                      #
#########################################################

# PORTSCAN_DETECT 链规则
$IPTABLES -A PORTSCAN_DETECT -m recent --set --name portscan --rsource
$IPTABLES -A PORTSCAN_DETECT -m recent --update --seconds 60 --hitcount $PORTSCAN_LIMIT --name portscan --rsource -j LOG --log-prefix "PORTSCAN_BLOCK: " --log-level 4
$IPTABLES -A PORTSCAN_DETECT -m recent --update --seconds 60 --hitcount $PORTSCAN_LIMIT --name portscan --rsource -j DROP
$IPTABLES -A PORTSCAN_DETECT -j RETURN

# SYN_FLOOD 链规则
$IPTABLES -A SYN_FLOOD -m limit --limit $SYN_FLOOD_LIMIT/s --limit-burst 10 -j RETURN
$IPTABLES -A SYN_FLOOD -m recent --set --name synflood --rsource
$IPTABLES -A SYN_FLOOD -m recent --update --seconds 10 --hitcount 20 --name synflood --rsource -j LOG --log-prefix "SYN_FLOOD: " --log-level 4
$IPTABLES -A SYN_FLOOD -m recent --update --seconds 10 --hitcount 20 --name synflood --rsource -j DROP
$IPTABLES -A SYN_FLOOD -j RETURN

#########################################################
# 日志规则（放在所有规则的最后）                        #
#########################################################

# 记录被拒绝的连接（放在所有规则的最后）
$IPTABLES -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPTABLES_DROP: " --log-level 4

#########################################################
# 智能安装和配置Fail2ban                                #
#########################################################

setup_fail2ban() {
    if ! command -v fail2ban-server &> /dev/null; then
        echo "安装Fail2ban..."
        apt update >/dev/null 2>&1
        apt install -y fail2ban >/dev/null 2>&1
        echo "Fail2ban 安装完成"
    else
        echo "Fail2ban 已安装，跳过安装"
    fi

    if [ ! -d "/etc/fail2ban/jail.d" ]; then
        mkdir -p /etc/fail2ban/jail.d
    fi

    if [ ! -f "$FAIL2BAN_JAIL" ] || ! grep -q "firewall-portscan" "$FAIL2BAN_JAIL"; then
        cat > $FAIL2BAN_JAIL << EOF
[sshd]
enabled = true
port = ${OPEN_PORTS["SSH"]}
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600

[nginx-http-auth]
enabled = true
port = ${OPEN_PORTS["HTTP"]},${OPEN_PORTS["HTTPS"]}
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600

[firewall-portscan]
enabled = true
filter = portscan
logpath = /var/log/firewall/scan/portscan.log
maxretry = 1
bantime = 86400
EOF
        echo "Fail2ban 配置已更新"
    else
        echo "Fail2ban 配置已存在，跳过配置"
    fi

    if systemctl is-active --quiet fail2ban; then
        echo "重启Fail2ban服务..."
        systemctl restart fail2ban
    else
        echo "启动Fail2ban服务..."
        systemctl enable --now fail2ban
    fi
}

#########################################################
# 智能安装网络监控工具                                  #
#########################################################

setup_monitoring() {
    check_command_exists "nethogs" "nethogs"
    check_command_exists "iftop" "iftop"
    check_command_exists "vnstat" "vnstat"

    local monitor_script="/usr/local/bin/network_monitor.sh"
    if [ ! -f "$monitor_script" ]; then
        cat > $monitor_script << 'EOF'
#!/bin/bash
LOG_DIR="/var/log/firewall/traffic"
mkdir -p $LOG_DIR

while true; do
    # 记录连接数
    netstat -an | grep ESTABLISHED | wc -l >> $LOG_DIR/connections.log
    # 记录带宽使用
    vnstat -tr 5 >> $LOG_DIR/bandwidth.log
    sleep 30
done
EOF
        chmod +x $monitor_script
        echo "网络监控脚本已创建"
    else
        echo "网络监控脚本已存在"
    fi

    if ! pgrep -f "network_monitor.sh" > /dev/null; then
        nohup $monitor_script > /dev/null 2>&1 &
        echo "网络监控已启动"
    fi
}

#########################################################
# 检查并安装必要的基础软件包                            #
#########################################################

install_prerequisites() {
    echo "检查系统必要软件包..."
    
    if ! dpkg -l | grep -q "iptables-persistent"; then
        echo "安装iptables-persistent..."
        apt update >/dev/null 2>&1
        debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v4 boolean true"
        debconf-set-selections <<< "iptables-persistent iptables-persistent/autosave_v6 boolean true"
        apt install -y iptables-persistent >/dev/null 2>&1
    fi

    check_command_exists "curl" "curl"
    check_command_exists "wget" "wget"
    check_command_exists "netstat" "net-tools"
}

#########################################################
# 保存规则和启动服务                                    #
#########################################################

save_iptables_rules() {
    mkdir -p /etc/iptables
    iptables-save > /etc/iptables/rules.v4
    
    if command -v netfilter-persistent &> /dev/null; then
        netfilter-persistent save
    fi
    
    echo "iptables规则已保存"
}

#########################################################
# 显示当前开放的端口列表                                #
#########################################################

show_open_ports() {
    echo "当前开放的端口列表:"
    echo "===================="
    for service in "${!OPEN_PORTS[@]}"; do
        echo "$service: ${OPEN_PORTS[$service]}/tcp"
    done
    if [[ -n "$P2P_TCP_PORTS" ]]; then
        echo "P2P_TCP: $P2P_TCP_PORTS"
    fi
    if [[ -n "$P2P_UDP_PORTS" ]]; then
        echo "P2P_UDP: $P2P_UDP_PORTS"
    fi
    echo "===================="
}

#########################################################
# 验证防火墙规则                                        #
#########################################################

validate_iptables_rules() {
    echo "验证防火墙规则..."
    
    if ! $IPTABLES -L PORTSCAN_DETECT > /dev/null 2>&1; then
        echo "错误: PORTSCAN_DETECT 链不存在"
        return 1
    fi
    
    if ! $IPTABLES -L SYN_FLOOD > /dev/null 2>&1; then
        echo "错误: SYN_FLOOD 链不存在"
        return 1
    fi
    
    for service in "${!OPEN_PORTS[@]}"; do
        port=${OPEN_PORTS[$service]}
        if ! $IPTABLES -L INPUT -n | grep -q "dpt:$port.*ACCEPT"; then
            echo "警告: 端口 $port 的ACCEPT规则可能未正确设置"
        fi
    done
    
    echo "防火墙规则验证完成"
    return 0
}

#########################################################
# IPv6防护（可选）                                      #
#########################################################

setup_ipv6_protection() {
    if command -v $IP6TABLES &> /dev/null; then
        echo "设置IPv6防护..."
        $IP6TABLES -P INPUT DROP
        $IP6TABLES -P FORWARD DROP
        $IP6TABLES -P OUTPUT ACCEPT
        $IP6TABLES -A INPUT -i lo -j ACCEPT
        $IP6TABLES -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
        echo "IPv6防护已设置"
    else
        echo "ip6tables不可用，跳过IPv6防护设置"
    fi
}

#########################################################
# 主执行逻辑                                            #
#########################################################

main() {
    echo "开始部署高级入侵防护系统..."
    echo "时间: $(date)"
    echo "=============================================="

    show_open_ports
    install_prerequisites

    echo "设置防火墙规则..."
    validate_iptables_rules

    echo "配置Fail2ban..."
    setup_fail2ban

    echo "设置网络监控..."
    setup_monitoring

    echo "设置IPv6防护..."
    setup_ipv6_protection

    echo "保存iptables规则..."
    save_iptables_rules

    if [ ! -f "/etc/logrotate.d/firewall" ]; then
        cat > /etc/logrotate.d/firewall << EOF
/var/log/firewall/*.log {
    daily
    missingok
    rotate 7
    compress
    delaycompress
    notifempty
    create 640 root adm
}
EOF
        echo "日志轮转配置已创建"
    fi

    echo "=============================================="
    echo "高级入侵防护系统部署完成!"
    echo "监控日志位于: $LOG_DIR"
    echo "使用 'fail2ban-client status' 查看封禁状态"
    echo "使用 'systemctl status fail2ban' 检查服务状态"
    echo "使用 'iptables -nL' 查看防火墙规则"
    echo "时间: $(date)"
}

# 执行主函数
main >> $LOG_DIR/firewall.log 2>&1

# 显示最终的防火墙规则状态
echo "最终的防火墙规则:"
$IPTABLES -nL

exit 0